/**
 * 
 */
package com.gragra.sequentiaDataGenerator;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Collection;
import java.util.regex.Pattern;
import com.gragra.data.Corpus;
import com.gragra.data.MixingCorpus;
import com.gragra.data.MixingCorpusBaseImplementation;
import com.gragra.sampling.sequentialStructure.ExtensionInformationValue;
import com.gragra.sampling.sequentialStructure.ExtensionLevels;
import com.gragra.sampling.sequentialStructure.WordAndTagHolder;
import com.gragra.util.StringToInt;
/**
 * This class is the basis for adding WordAndTagHolder to a corpus by constructing WordAndTagHolder from
 * lines in a BufferedReader the main method that defines the behavior of the method
 * @author Christoph Teichmann
 * created Mar 26, 2013 2:43:26 PM
 * @version 0.1
 */
public class BaseGenerator
{
	/**
	 * creates a new generator that will use the given segmenter to transfer elements to information
	 * @param segm
	 */
	public BaseGenerator(Segmentation segm)
	{this.segm = segm;}
	/**
	 * list used to hold all currently used String arrays
	 */
	private final ObjectArrayList<String[]> list = new ObjectArrayList<String[]>();
	/**
	 * the approach to segmentation that will be used
	 */
	private final Segmentation segm;
	/**
	 * this method creates a new corpus and adds new WordAndTagHolder to it according to the
	 * extendCorpus method
	 *
	 * @param fromInput
	 * @return
	 * @throws IOException 
	 */
	public MixingCorpus<WordAndTagHolder> createCorpus(BufferedReader fromInput) throws IOException
	{
		MixingCorpus<WordAndTagHolder> wth = new MixingCorpusBaseImplementation<WordAndTagHolder>();
		this.extendCorpus(fromInput, wth);
		return wth;
	}
	/**
	 * transforms all the non-empty lines from the corpus to WordAndTagHolder and adds them in order to the
	 * given corpus, the convergence is done via the transferSingle method
	 *
	 * @param fromInput
	 * @param toExtend
	 * @throws IOException 
	 */
	public void extendCorpus(BufferedReader fromInput,Corpus<WordAndTagHolder> toExtend) throws IOException
	{
		String line;
		while((line = fromInput.readLine()) != null)
		{
			line = line.trim();
			if(!line.isEmpty())
			{toExtend.addData(this.transferSingle(line));}
		}
	}
	/**
	 * the pattern which all lines have to conform to, requires that each line contains some tag for a word
	 * and that there are no empty lines
	 */
	private Pattern pa = Pattern.compile("([^\\s]+\\|[^\\s]+\\s*)+");
	/**
	 * this method is used to create a new WordAndTagStructure from a given line,
	 * the string is first split on whitespace and then each element is transferred to a
	 * collection of string arrays by the used Segmentation instance each array in the collection
	 * is used to create an additional entry in WordAndTagHolder, first String in an array is the word,
	 * second is the tag, both are segmented by "|" then follows the tag both MUST be present, but NONE 
	 * can be used to indicate an absent tag, then additional information can follow, usually by a series
	 * of ExtensionLevel instance | value of the ExtensionLevel, the segmenter must return the arrays in the
	 * collection with a similar structure of word,tag or NONE, then series of ExtensionLevel and ExtensionLevel;
	 * note that ExtensionLevel - Value pairs are processed in order from left to right and new values for Levels
	 * already processed are used to overwrite the old levels
	 * values
	 * @return
	 */
	public WordAndTagHolder transferSingle(String line)
	{
		if(!pa.matcher(line.trim()).matches())
		{throw new IllegalArgumentException("no empty strings as arguments and all words need tags, even if it is just NONE");}
		String[] parts = line.trim().split("\\s+");
		list.clear();
		for(int i=0;i<parts.length;++i)
		{
			String s = parts[i];
			Collection<String[]> segment = segm.segment(s);
			list.addAll(segment);
		}
		int[][] arr = new int[list.size()][];
		int index = 0;
		for (String[] sarr : list)
		{
			int[] cont = new int[sarr.length];
			cont[0] = StringToInt.ensure(sarr[0]);
			if(!(sarr[1].equals("NONE")))
			{cont[1] = StringToInt.ensure(sarr[1]);}
			else
			{cont[1] = -1;}
			for(int i=2;i<sarr.length-1;i += 2)
			{
				ExtensionLevels level = ExtensionLevels.valueOf(sarr[i]);
				int one = level.getNumber();
				int two;
				if(level.isFinite())
				{
					ExtensionInformationValue eiv = level.getValueClass(sarr[i+1]);
					two = eiv.getNumber();
				}
				else
				{two = Integer.parseInt(sarr[i+1]);}
				cont[i] = one;
				cont[i+1] = two;
			}
			arr[index++] = cont;
		}
		return new WordAndTagHolder(arr);
	}
	/**
	 * returns a string representation of the given structure and the information contained in it in such
	 * a way that it could be read by this class by using a EmptySegmentation
	 * @param wta
	 * @return
	 */
	public static String transferToString(WordAndTagHolder wta)
	{
		StringBuilder sb = new StringBuilder();
		boolean first = true;
		for(int i=0;i<wta.getLength();++i)
		{
			if(first)
			{first = false;}
			else
			{sb.append(" ");}
			sb.append(wta.getWordString(i));
			sb.append("|");
			sb.append(wta.getTagString(i));
			sb.append(wta.getExtensionInformation().getCombinedString(i));
		}
		return sb.toString();
	}
}